from PyQt5.QtCore import QThread, pyqtSignal


class AsyncTask(QThread):
    """异步任务类"""
    # 无参 信号
    signal = pyqtSignal()

    # 标志位信号
    signal_int = pyqtSignal([int])

    # 列表信号
    signal_list = pyqtSignal([list])

    # 字典信号
    signal_dict = pyqtSignal([dict])

    # 意外信号
    signal_exception = pyqtSignal([Exception])

    # 进度信号 如：5, 100, 自定义消息
    signal_progress = pyqtSignal([int, int, str])

    # 任务对象
    runnable = None

    def __init__(self):
        super(AsyncTask, self).__init__()

    def run(self):
        if self.runnable:
            try:
                self.runnable()
            except Exception as e:
                self.signal_exception.emit(e)

    def _new_runnable(self, runnable):
        def _runnable():
            runnable(self)
            self.signal.emit()

        return _runnable

    def _new_int_runnable(self, runnable):
        return lambda: self.signal_int.emit(runnable(self))

    def _new_dict_runnable(self, runnable):
        return lambda: self.signal_dict.emit(runnable(self))

    def _new_list_runnable(self, runnable):
        return lambda: self.signal_list.emit(runnable(self))

    @staticmethod
    def create(runnable, except_callback):
        task = AsyncTask()
        task.runnable = task._new_runnable(runnable)
        task.signal_exception.connect(except_callback)
        return task

    @staticmethod
    def create_int(runnable, callback, except_callback):
        task = AsyncTask()
        task.runnable = lambda: task.signal_int.emit(runnable())
        task.signal_int.connect(callback)
        task.signal_exception.connect(except_callback)
        return task

    @staticmethod
    def create_list(runnable, callback, except_callback):
        task = AsyncTask()
        task.runnable = task._new_list_runnable(runnable)
        task.signal_list.connect(callback)
        task.signal_exception.connect(except_callback)
        return task

    @staticmethod
    def create_dict(runnable, callback, except_callback):
        task = AsyncTask()
        task.runnable = lambda: task.signal_dict.emit(runnable())
        task.signal_dict.connect(callback)
        task.signal_exception.connect(except_callback)
        return task
